package main

import (
	"GameServer/Game/sp"
	"GameServer/Protocol/protocol/sproto"

	"fmt"
	"log"
	"net"
	"sync"
)

type IClient interface {
	Start()                   // 开始连接服务器
	Close()                   // 停止连接
	WriteMsg(msg interface{}) // 发送数据
}

type Client struct {
	closeOnce sync.Once
	conn      net.Conn
	protocl   *sproto.SprotoPtotocol
	closeChan chan bool
	recv      chan interface{}
	send      chan interface{}
}

func NewClient() (r IClient) {
	r = &Client{
		closeChan: make(chan bool),
		recv:      make(chan interface{}, 20),
		send:      make(chan interface{}, 20),
	}
	return
}

func (this *Client) Start() { // 开始连接服务器
	// 连接服务器
	conn, err := net.Dial("tcp", "srv0.rockmango.com:5555")
	if err != nil {
		fmt.Println(err)
		return
	}
	this.conn = conn
	// 创建协议
	this.protocl = sproto.NewSprotoPtotocol(sp.Protocols)

	go this.writeLoop()
	go this.handleLoop()
	go this.readLoop()
}

func (this *Client) Close() { // 停止连接
	this.closeOnce.Do(func() {
		close(this.closeChan) //关闭管道，相关的协程都会停止运行
		this.conn.Close()     //关闭连接
		log.Println("断开连接....")
	})
}

func (this *Client) writeLoop() { // 发送数据
	defer this.Close()

	for {
		select {
		case <-this.closeChan:
			return
		case msg := <-this.send:
			b, err := this.marshal(msg)
			if err != nil {
				fmt.Println(err)
				break
			}
			if err := this.write(b); err != nil {
				fmt.Println(err)
				return
			}
			fmt.Printf("写入...%+v\n", msg)
		}
	}
}

func (this *Client) readLoop() { // 接受数据
	defer this.Close()

	for {
		select {
		case <-this.closeChan:
			return
		default:
		}

		b, err := this.read()
		if err != nil {
			fmt.Println(err)
			return
		}
		msg, err := this.unmarshal(b)
		if err != nil {
			fmt.Println(err)
			continue
		}
		fmt.Printf("读取...%+v\n", msg)
		this.recv <- msg
	}
}

func (this *Client) handleLoop() {
	defer this.Close()

	for {
		select {
		case <-this.closeChan:
			return
		case msg := <-this.recv:
			fmt.Printf("处理...%+v\n", msg)
		}
	}
}

func (this *Client) WriteMsg(msg interface{}) {
	this.send <- msg
}

func (this *Client) read() (r []byte, err error) {
	r, err = this.protocl.Read(this.conn)
	return
}

func (this *Client) write(b [][]byte) (err error) {
	if err = this.protocl.Write(this.conn, b...); err != nil {
		return
	}
	return
}

func (this *Client) unmarshal(b []byte) (r interface{}, err error) {
	return this.protocl.Unmarshal(b)
}

func (this *Client) marshal(msg interface{}) ([][]byte, error) {
	return this.protocl.Marshal(msg)
}
